#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <math.h>

#define TYPE double
#define NUM_THREADS 2

// this test checks the performance of the sequential and parallel
// implementation.  This is done to check the performance characteristics
// with different sizes of input.


// the use must define this function to use genericScan
//void userBinaryOperator( void *x1, void *x2) {
//	TYPE *a = (TYPE *) x1;
//	TYPE *b = (TYPE *) x2;
//	
//	*a += *b;
//}

void seqScan(TYPE *X, unsigned int n, unsigned int offset, unsigned int stride);

void tweakedScan(TYPE *X, int n);

void tweakedScanBitOps(TYPE *X, int n);

void hybridScan(TYPE *X, int n, int blockBits);
void hybridScan2(TYPE *X, int n, int blockBits);


// DRIVER
int main( int argc, char **argv) {	
	
	// problem setup
	int n = 50000000;
	int dim = 1;
	int i;

	if(argc > 1) 
		n = atoi(argv[1]);

	if(argc > 2) 
		dim = atoi(argv[2]);
		
	TYPE *x = (TYPE *) malloc( sizeof(TYPE) * n);
	
	
	for(i = 0; i < n; i++)
		x[i] = i % 2;


/*
	// print input
	printf("Input array:\n");
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/

	//omp_set_nested(1);
	//omp_set_dynamic(1);

	// scan with timing
	double t1 = omp_get_wtime(); 
	seqScan(x, n, 0, 1);
	double t2 = omp_get_wtime();

	
	
/*
	//print output
	printf("Output array:\n");	
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/
	printf("\nseq scan Took %g secs for %d keys\n", t2-t1, n);

	for(i = 0; i < n; i++)
		x[i] = i % 2;
/*
	// print input
	printf("Input array:\n");
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/

	//omp_set_nested(1);
	//omp_set_dynamic(1);

	// scan with timing
	t1 = omp_get_wtime(); 
	tweakedScan(x, n);
	t2 = omp_get_wtime();

	
	
/*
	//print output
	printf("Output array:\n");	
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/
	printf("\n\ttweaked scan Took %g secs for %d keys\n", t2-t1, n);

	for(i = 0; i < n; i++)
		x[i] = i % 2;
/*
	// print input
	printf("Input array:\n");
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/

	//omp_set_nested(1);
	//omp_set_dynamic(1);

	// scan with timing
	t1 = omp_get_wtime(); 
	tweakedScanBitOps(x, n);
	t2 = omp_get_wtime();

	
	
/*
	//print output
	printf("Output array:\n");	
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/
	printf("\n\tbit scan Took %g secs for %d keys\n", t2-t1, n);

	
		for(i = 0; i < n; i++)
		x[i] = i % 2;
/*
	// print input
	printf("Input array:\n");
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/

	//omp_set_nested(1);
	//omp_set_dynamic(1);

	// scan with timing
	t1 = omp_get_wtime(); 
	hybridScan(x, n, 13);
	t2 = omp_get_wtime();

	
	
/*
	//print output
	printf("Output array:\n");	
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/
	printf("\n\thybrid scan Took %g secs for %d keys\n", t2-t1, n);

		for(i = 0; i < n; i++)
		x[i] = i % 2;
/*
	// print input
	printf("Input array:\n");
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/

	//omp_set_nested(1);
	//omp_set_dynamic(1);

	// scan with timing
	t1 = omp_get_wtime(); 
	hybridScan2(x, n, 13);
	t2 = omp_get_wtime();

	
	
/*
	//print output
	printf("Output array:\n");	
	for(i = 0; i < n; i++) 
		printf("%.0f ", x[i]); 	
	printf("\n");
*/
	printf("\n\thybrid scan 2 Took %g secs for %d keys\n", t2-t1, n);
	
	
	// clean up
	free(x);
	return 0;
}
	




	


	



